import re 
import sys

class ValidationResult(object):
	def __init__(self, original_value, opt_value=None, opt_errors=[]):
		self.original_value = original_value
		self.value = None
		if not opt_errors:
			self.value = opt_value
		self.errors = opt_errors

	def is_valid(self):
		return len(self.errors) == 0 

	def get_last_error(self):
		if self.errors:
			return self.errors[-1]
		return None

class ValidationChain(object):
	def __init__(self, validators):
		self.validators = validators

	def validate(self, value):
		result = ValidationResult(True, value) 
		for validator in self.validators:
			result = validator.validate(result.value)			
			if not result.is_valid():
				break
		return result

class ValidationRequest(object):
	def __init__(self):
		self.fields = {}

	def expect_field(self, key, validators):
		self.fields[key] = ValidationChain(validators)

	def validate(self, request):
		result = ValidationResponse()
		for (key, chain) in self.fields.iteritems():
			result.append_result(key, chain.validate(request.get(key, None)))
		return result			

class ValidationResponse(object):
	def __init__(self):
		self.results = {}

	def is_valid(self):
		for result in self.results.values():
			if not result.is_valid():
				return False
		return True

	def append_result(self, key, result):
		if self.results.has_key(key):
			raise KeyError("Duplicate key")
		self.results[key] = result
	
	def get_value(self, key, opt_default=None):
		result = self.results.get(key)
		if result and result.is_valid():
			return result.value
		return opt_default

	def get(self, key):
		return self.results.get(key, None)

class ValidationError(Exception):
	def __init__(self, message):
		self.message = message
		
class Validator(object):
	def validate(self, value):
		result_value = None
		errors = []
		try:
			result_value = self.do_validate(value)
		except ValidationError, err:
			errors.append(err.message)
		return ValidationResult(value, result_value, errors)

	def do_validate(self, value):
		return value

class RequiredValidator(Validator):
	def do_validate(self, value):
		if not value:
			raise ValidationError("Field is required.")
		return value

class StringRegexValidator(Validator):
	def __init__(self, regex):
		self.regex = regex

	def do_validate(self, value):
		if value == None:
			return None
		if not re.compile(self.regex).match(value):
			raise ValidationError("Field must match '%s'." % self.regex)
		return value
		
class StringLengthValidator(Validator):
	def __init__(self, min=0, max=sys.maxint):
		self.min = min
		self.max = max

	def do_validate(self, value):
		if value == None:
			return None
		if len(value) < self.min or len(value) > self.max:
			raise ValidationError("Field must between %d and %d characters long." % (self.min, self.max))
		return value

class StringExactMatchValidator(Validator):
	def __init__(self, match):
		self.match = match

	def do_validate(self, value):
		if value == None:
			return None
		if self.match != value:
			raise ValidationError("Field must match '%s' exactly." % (self.match))
		return value

class StringEnumerationValidator(Validator):
	def __init__(self, values):
		self.values = values

	def do_validate(self, value):
		if value == None:
			return None
		if value not in self.values:
			raise ValidationError("Field must match one of %s." % (str(self.values)))
		return value

class IntegerValidator(Validator):
	def do_validate(self, value):
		if value == None or value == "":
			return None
		result_value = 0
		try:
			result_value = int(value)
		except ValueError:
			raise ValidationError("Field must convert to an integer.")
		return result_value

class IntegerRangeValidator(IntegerValidator):
	def __init__(self, min=0, max=sys.maxint):
		self.min = min
		self.max = max

	def do_validate(self, value):
		if value == None:
			return None
		if value < self.min or value > self.max:
			raise ValidationError("Field must be between %d and %d." % (self.min, self.max))
		return value
